#pragma once

#include<vector>
#include<string>
#include<unordered_map>
#include<brpc/channel.h>
#include<memory>
#include<mutex>
#include<unordered_set>

#include "logger.hpp"

namespace xu
{
    class ServiceChannel
    {
    public:
        using ptr = std::shared_ptr<ServiceChannel>;
        using ChannelPtr = std::shared_ptr<brpc::Channel>;
        ServiceChannel(const std::string& serviec_name)
        :_service_name(serviec_name),
        _index(0)
        {}
        void Append(const std::string & host)
        {
            //1.构建信道
            brpc::ChannelOptions options;
            options.connect_timeout_ms = -1;
            options.timeout_ms = -1;
            options.max_retry = 3;
            options.protocol = "baidu_std";
            ChannelPtr channel_ptr = std::make_shared<brpc::Channel>();
            channel_ptr->Init(host.c_str(),&options);

            //2.管理信道
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service_channel.insert(std::make_pair(host,channel_ptr));
                _channels.push_back(channel_ptr);
            }
        }

        void Remove(const std::string & host)
        {
            std::unique_lock<std::mutex> lock(_mutex);

            //1.找到信道
            auto it = _service_channel.find(host);
            if(it == _service_channel.end())
            {
                LOG_WARN("主机：{} 没有找到对应的Channel",host);
                return;
            }

            //2.删除信道
            for(auto i = _channels.begin(); i != _channels.end(); ++i)
            {
                if(*i == it->second)
                {
                    _channels.erase(i);
                    break;
                }
            }

            _service_channel.erase(host);
        }

        ChannelPtr Choose()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_channels.empty())
            {
                LOG_INFO("{}服务目前没有提供方",_service_name);
                return ChannelPtr();
            }
            int i = _index++ %  _channels.size();   //RR轮转方式
            return _channels[i];
        }

    private:
        std::string _service_name;  //服务名称
        int _index;                 //索引
        std::vector<ChannelPtr> _channels;  //管理信道
        std::unordered_map<std::string,ChannelPtr> _service_channel;    //映射方便找到信道
        std::mutex _mutex;          //锁
    };

    class ServiceManage
    {
    public:
        using ptr = std::shared_ptr<ServiceManage>;
        ServiceManage(){};
        void AddFollow(const std::string & service_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _service_follow.insert(service_name);
        }
        void onServiceOnline(const std::string & service_instance, const std::string & host)
        {
            std::string service_name = getServiceName(service_instance);
            ServiceChannel::ptr service_channel;   
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto itsf = _service_follow.find(service_name);
                if(itsf == _service_follow.end())
                {
                    LOG_INFO("不关心：{}服务",service_name);
                    return;
                }

                auto it = _service_channels.find(service_name);
                if(it == _service_channels.end())
                {
                    service_channel = std::make_shared<ServiceChannel>(service_name);
                    _service_channels.insert(std::make_pair(service_name,service_channel));
                }
                else
                {
                    service_channel = it->second;
                }
            }

            service_channel->Append(host);
        }
        void onServiceOffline(const std::string & service_instance, const std::string & host)
        {
            std::string service_name = getServiceName(service_instance);
            ServiceChannel::ptr service_channel;   
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto itsf = _service_follow.find(service_name);
                if(itsf == _service_follow.end())
                {
                    LOG_INFO("不关心：{}服务",service_name);
                    return;
                }

                auto it = _service_channels.find(service_name);
                if(it == _service_channels.end())
                {
                    LOG_WARN("{}服务找不到",service_name);
                    return;
                }
                service_channel = it->second;
                LOG_INFO("服务{} : {} 下线",service_name,host);
            }
            service_channel->Remove(host);
            LOG_INFO("服务{} : {} 下线",service_name,host);
        }
        ServiceChannel::ChannelPtr Choose(const std::string & service_name)
        {
            ServiceChannel::ptr service_channel;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _service_channels.find(service_name);
                if(it == _service_channels.end())
                {
                    LOG_WARN("没有找到对应的{}",service_name);
                    return ServiceChannel::ChannelPtr();
                }
                service_channel = it->second;
            }

            return  service_channel->Choose();
        }
    private:
        std::string getServiceName(const std::string & service_instance)
        {
            auto pos = service_instance.find_last_of('/');
            if(pos == std::string::npos)
            {
                return service_instance;
            }
            return service_instance.substr(0,pos);
        }
    private:
        std::mutex _mutex;
        std::unordered_map<std::string,ServiceChannel::ptr> _service_channels;
        std::unordered_set<std::string> _service_follow;
    };
}